import java.awt.Point;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

public class SelectionEventProcessor extends DrawObjectEventProcessor
{
	// CALL METHODS OF THIS "SELECTION" EVENT PROCESSOR EARLY!
	// (sets some flags and objects required by the specialized DrawObjectEventProcessors!)

	@Override
	public void TryProcessUserKeyboardAction(MainWindow.GUIElements GUIElements, KeyEventProcessor KeyEventProcessor, MouseEventProcessor MouseEventProcessor, ObjectStorage ObjectStorage, IOProgram IOProgram)
	{
		if (!(KeyboardEventsToBeProcessed(GUIElements)))
			return;

		// ****************************************************************
		// ESC (end multi-selection)
		if (KeyEventProcessor.IsKeyCodePressed(KeyEvent.VK_ESCAPE))
		{
			if (MultiSelectionExisting)
			{
				MultiSelectionExisting = false;

				Selection = UNDEFINED_SELECTION;

				ObjectStorage.UnHighlightAllObjects();
				ObjectStorage.UnSetPartOfMultiSelectionForAllObjects();

				GUIElements.GetMainWindow().DoRedraw();
			}
		}

		return;
	}

	@Override
	public void TryProcessUserMouseAction(MainWindow.GUIElements GUIElements, KeyEventProcessor KeyEventProcessor, MouseEventProcessor MouseEventProcessor, ObjectStorage ObjectStorage, IOProgram IOProgram)
	{
		if (!(MouseEventsToBeProcessed(GUIElements)))
			return;

		if (MouseEventProcessor.IsMouseMoved() &&
			NOT(MouseEventProcessor.AnyButtonPressed()))
		{
			SingleSelectedObjectOffset = null;
		}

		// ****************************************************************
		if (NOT(MouseEventProcessor.IsMouseDragged()) &&
			MouseEventProcessor.AnyButtonPressed())
		{
			DrawObject SingleSelectedObjectOld = SingleSelectedObject;

			SingleSelectedObject = ObjectStorage.TrySelectDrawObject(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())));

			if (DEFINED(SingleSelectedObject))
			{
				if (SingleSelectedObject != SingleSelectedObjectOld)
				{
					GUIElements.GetMainWindow().DoRedraw();
				}
			}
		}
		// ****************************************************************
		if (MouseEventProcessor.IsLeftButtonDown())
		{
			if (DEFINED(SingleSelectedObject) &&
				UNDEFINED(SingleSelectedObjectOffset))
			{
				SingleSelectedObjectOffset = Tools.SubtractPoints(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())), SingleSelectedObject.Pos);
			}
		}
		// ****************************************************************
		if (MouseEventProcessor.IsLeftButtonDown() &&
			NOT(KeyEventProcessor.IsControlPressed()) &&
			KeyEventProcessor.IsShiftPressed()) // Shift and Control at the same time is currently not supported
		{
			if (UNDEFINED(Selection))
			{
				ObjectStorage.UnSetPartOfMultiSelectionForAllObjects(); // do this to avoid any confusion of system ;-P

				NearObject = UNDEFINED;
				
				SingleSelectedObject = UNDEFINED;
				SingleSelectedObjectOffset = UNDEFINED_POINT;
				
				Selection = new Selection(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())));
				Selection.SetEndPoint(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())));

				ObjectStorage.AddObjectDirectly(Selection);

				GUIElements.GetMainWindow().DoRedraw();
			}
			else
			{
				Point EndPointNew = DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow()));
				if (EndPointNew != Selection.GetEndPoint())
				{
					Selection.SetEndPoint(EndPointNew);

					ArrayList<DrawObject> MultiSelectionObjects = ObjectStorage.GetSelectionObjects(Selection.Pos, Selection.Size);

					ObjectStorage.UnSetPartOfMultiSelectionForAllObjects();

					for (int i = 0; i < MultiSelectionObjects.size(); i++)
					{
						MultiSelectionObjects.get(i).SetPartOfMultiSelection(true);
					}

					GUIElements.GetMainWindow().DoRedraw();
				}
			}

			MoveMousePosLast = UNDEFINED_POINT; // no button pressed, no moving!
		}
		// ****************************************************************
		if (MouseEventProcessor.IsLeftButtonDown() &&
			KeyEventProcessor.IsControlPressed() &&
			NOT(KeyEventProcessor.IsShiftPressed())) // Shift and Control at the same time is currently not supported
		{
			if (DEFINED(SingleSelectedObject))
			{
				if (SingleSelectedObject.CanBeSelectedByUser())
				{
					if (NOT(SingleSelectedObject.IsPartOfMultiSelection()))
					{
						SingleSelectedObject.SetPartOfMultiSelection(true);

						GUIElements.GetMainWindow().DoRedraw();
					}
					else
					{
						SingleSelectedObject.SetPartOfMultiSelection(false);

						GUIElements.GetMainWindow().DoRedraw();
					}
				}
			}

			if (DEFINED(MoveMousePosLast))
			{
				Point MousePosLastAligned = DrawObject.AlignOnGrid(DrawObject.UnZoomPoint(MoveMousePosLast));
				Point MousePosAligned = DrawObject.AlignOnGrid(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())));

				if (MousePosAligned.x != MousePosLastAligned.x || MousePosAligned.y != MousePosLastAligned.y)
				{
					ObjectStorage.MoveMultiSelection(Tools.SubtractPoints(MousePosAligned, MousePosLastAligned));

					GUIElements.GetMainWindow().DoRedraw();
				}
			}

			MoveMousePosLast = MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow()); // do NOT zoom!
		}
		// ****************************************************************
		if (MouseEventProcessor.IsLeftButtonDown() &&
			NOT(KeyEventProcessor.IsControlPressed()) &&
			NOT(KeyEventProcessor.IsShiftPressed()))
		{
			if (MultiSelectionExisting)
			{
				if (DEFINED(MoveMousePosLast))
				{
					Point MousePosLastAligned = DrawObject.AlignOnGrid(DrawObject.UnZoomPoint(MoveMousePosLast));
					Point MousePosAligned = DrawObject.AlignOnGrid(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())));

					if (MousePosAligned.x != MousePosLastAligned.x || MousePosAligned.y != MousePosLastAligned.y)
					{
						ObjectStorage.MoveMultiSelection(Tools.SubtractPoints(MousePosAligned, MousePosLastAligned));

						GUIElements.GetMainWindow().DoRedraw();
					}
				}
			}
			else if (DEFINED(SingleSelectedObject))
			{
				if (SingleSelectedObject.CanBeMovedByUser())
				{
					Point PosNew = // DO NOT ALIGN HERE! In tests, objects got moved when trying to draw Lines, if aligning PosNew!
						Tools.SubtractPoints(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())), SingleSelectedObjectOffset);

					if (PosNew.x != SingleSelectedObject.Pos.x || PosNew.y != SingleSelectedObject.Pos.y)
					{
						SingleSelectedObject.SetPos(PosNew);

						LineStart = UNDEFINED;

						GUIElements.GetMainWindow().DoRedraw();
					}
				}
			}

			MoveMousePosLast = MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow()); // do NOT zoom!
		}
		// ****************************************************************
		if (MouseEventProcessor.IsRightButtonDown())
		{
			if (DEFINED(MoveMousePosLast))
			{
				Point MousePosLastAligned = DrawObject.AlignOnGrid(DrawObject.UnZoomPoint(MoveMousePosLast));
				Point MousePosAligned = DrawObject.AlignOnGrid(DrawObject.UnZoomPoint(MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow())));

				if (MousePosAligned.x != MousePosLastAligned.x || MousePosAligned.y != MousePosLastAligned.y)
				{
					ObjectStorage.MoveAll(Tools.SubtractPoints(MousePosAligned, MousePosLastAligned));

					if (DEFINED(Selection))
					{
						Selection.Move(Tools.SubtractPoints(MousePosAligned, MousePosLastAligned));
					}

					GUIElements.GetMainWindow().DoRedraw();
				}
			}

			MoveMousePosLast = MouseEventProcessor.GetMousePosPoint(GUIElements.GetMainWindow()); // do NOT zoom!
		}
		// ****************************************************************
		if (MouseEventProcessor.NoButtonPressed())
		{
			if (DEFINED(Selection)) // delete selection rect if mouse button released
			{
				ObjectStorage.DeleteObject(Selection);

				Selection = UNDEFINED_SELECTION;

				GUIElements.GetMainWindow().DoRedraw();
			}
		}

		// ****************************************************************
		String SelectionInfoText = "ESC to deselect";
		if (MultiSelectionExisting)
		{
			GUIElements.GetMainWindow().GetTitleBarInfo().AddInfoText(SelectionInfoText, false, false, true, false); // show progress to make sure user realized he must do something with selection
		}
		else
		{
			GUIElements.GetMainWindow().GetTitleBarInfo().RemoveInfoText(SelectionInfoText);
		}

		return;
	}
}
